package io.renren.common.utils.docx;

import org.docx4j.Docx4J;
import org.docx4j.XmlUtils;
import org.docx4j.convert.out.FOSettings;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.wml.*;

import javax.imageio.stream.FileImageInputStream;
import javax.xml.bind.JAXBElement;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 模板word内容替换工具类
 */
public class Tool {
    //图片转为字节数组
    public static byte[] image2byte(String path) {
        byte[] data = null;
        FileImageInputStream input = null;
        try {
            input = new FileImageInputStream(new File(path));
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int numBytesRead = 0;
            while ((numBytesRead = input.read(buf)) != -1) {
                output.write(buf, 0, numBytesRead);
            }
            data = output.toByteArray();
            output.close();
            input.close();
        } catch (FileNotFoundException ex1) {
            ex1.printStackTrace();
        } catch (IOException ex1) {
            ex1.printStackTrace();
        }
        return data;
    }

    /**
     * 在标签处插入替换内容
     *
     * @param bm
     * @param object
     * @throws Exception
     */
    public static void replaceText(CTBookmark bm, String value) throws Exception {


        try {
            List<Object> theList = null;
            ParaRPr rpr = null;
            if (bm.getParent() instanceof P) {
                PPr pprTemp = ((P) (bm.getParent())).getPPr();
                if (pprTemp == null) {
                    rpr = null;
                } else {
                    rpr = ((P) (bm.getParent())).getPPr().getRPr();
                }
                theList = ((ContentAccessor) (bm.getParent())).getContent();
            } else {
                return;
            }
            int rangeStart = -1;
            int rangeEnd = -1;
            int i = 0;
            for (Object ox : theList) {
                Object listEntry = XmlUtils.unwrap(ox);
                if (listEntry.equals(bm)) {
                    if (((CTBookmark) listEntry).getName() != null) {
                        rangeStart = i + 1;
                    }
                } else if (listEntry instanceof CTMarkupRange) {
                    if (((CTMarkupRange) listEntry).getId().equals(bm.getId())) {
                        rangeEnd = i - 1;
                        break;
                    }
                }
                i++;
            }
            int x = i - 1;
            for (int j = x; j >= rangeStart; j--) {
                theList.remove(j);
            }

            ObjectFactory factory = Context.getWmlObjectFactory();
            org.docx4j.wml.R run = factory.createR();

            org.docx4j.wml.Text t = factory.createText();
            //设置插入的文本内容
            t.setValue(value);

            //设置插入的文本样式
            RPr runProperties = factory.createRPr();
            U val = new U();
            val.setVal(UnderlineEnumeration.WORDS);
            runProperties.setU(val);
            runProperties.setRFonts(new RFonts());

            run.getContent().add(t);
            run.setRPr(runProperties);

            theList.add(rangeStart, run);
        } catch (ClassCastException cce) {

        }
    }

    /**
     * 替换image
     *
     * @param wPackage
     * @param bm
     * @param file
     */
    public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm, String file) throws Exception {

        // 读入图片并转化为字节数组，因为docx4j只能字节数组的方式插入图片

        byte[] bytes = image2byte(file);
        // 创建一个行内图片
        BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wPackage, bytes);
        // createImageInline函数的前四个参数我都没有找到具体啥意思
        // 最有一个是限制图片的宽度，缩放的依据
        Inline inline = imagePart.createImageInline(null, null, 0, 1, false, 600);
        // 获取该书签的父级段落
        P p = (P) (bm.getParent());
        ObjectFactory factory = new ObjectFactory();
        // R对象是匿名的复杂类型，然而我并不知道具体啥意思，估计这个要好好去看看ooxml才知道
        R run = factory.createR();
        // drawing理解为画布
        Drawing drawing = factory.createDrawing();
        drawing.getAnchorOrInline().add(inline);

        RPr runProperties = factory.createRPr();
        U val = new U();
        val.setVal(UnderlineEnumeration.WORDS);
        runProperties.setU(val);
        run.getContent().add(drawing);
        run.setRPr(runProperties);
        p.getContent().add(run);
    }

    /**
     * 处理图片适应大小
     *
     * @param cx
     * @param cy
     * @param newCx
     * @param newCy
     */
    public static Map<String, Long> dealCxy(Long cx, Long cy, Long newCx, Long newCy) {
        Map<String, Long> map = new HashMap<>();
        Long setCx;
        Long setCy;

        if (newCx > cx) {
            if (newCy <= cy) {
                setCx = cx;
                setCy = newCy / (newCx / cx);
            } else {
                if ((newCx / cx) > (newCy / cy)) {
                    setCx = cx;
                    setCy = newCy / (newCx / cx);
                } else {
                    setCy = cy;
                    setCx = newCx / (newCy / cy);
                }
            }
        } else {   // newCx < cx
            if (newCy > cy) {
                setCx = cx;
                setCy = newCy * (cx / newCx);
            } else {
                if ((cx / newCx) > (cy / newCy)) {
                    setCx = cx;
                    setCy = newCy * (cx / newCx);
                } else {
                    setCy = cy;
                    setCx = newCy * (cy / newCy);
                }
            }
        }
        map.put("setCx", setCx);
        map.put("setCy", setCy);
        return map;
    }


    /**
     * 得到指定类型的元素
     *
     * @param obj
     * @param toSearch
     * @return
     */
    public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
        List<Object> result = new ArrayList<>();
        if (obj instanceof JAXBElement)
            obj = ((JAXBElement<?>) obj).getValue();
        if (obj.getClass().equals(toSearch))
            result.add(obj);
        else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }
        }
        return result;
    }

    /**
     * word 转换 pdf （实际是没有用到的）
     *
     * @param docxPath
     * @param pdfPath
     * @throws Exception
     */
    public static void convertDocxToPDF(String docxPath, String pdfPath) throws Exception {
        OutputStream os = null;
        try {
            WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(new File(docxPath));
            Mapper fontMapper = new IdentityPlusMapper();
            fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
            fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
            fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
            mlPackage.setFontMapper(fontMapper);

            os = new java.io.FileOutputStream(pdfPath);

            FOSettings foSettings = Docx4J.createFOSettings();
            foSettings.setWmlPackage(mlPackage);
            Docx4J.toFO(foSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL);

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {

        }
    }

    /**
     * 下载PDF文件（实际是没有用到的）
     *
     * @param wordMLPackage
     * @param os
     * @throws Exception
     */
    public void pdfFile(WordprocessingMLPackage wordMLPackage, OutputStream os) throws Exception {

        String regex = null;
        Mapper fontMapper = new IdentityPlusMapper();
        wordMLPackage.setFontMapper(fontMapper);
        PhysicalFont font = PhysicalFonts.get("Arial Unicode MS");
        String directory = "D:\\upload\\pdf";
        String fileName = "OUT_ConvertInXHTMLURL.pdf";
        File f = new File(directory, fileName);
        if (f.exists()) {
            // 文件已经存在，输出文件的相关信息
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getName());
            System.out.println(f.length());
        } else {
            //  先创建文件所在的目录
            f.getParentFile().mkdirs();
        }
        File file = new File(directory + "/" + fileName);
        OutputStream os34 = new java.io.FileOutputStream(file);
        Docx4J.toPDF(wordMLPackage, os34);
        os.flush();
        os.close();
        wordMLPackage = null;
    }


}